
import { director, find, log } from 'cc';
import web3 from 'web3/dist/web3.min.js'
import BigNumber from 'bignumber.js'
import UtilTool from '../../tools/UtilTool';
// const recABI = ABIInfo.rec20ABI;
// const gameABI = ABIInfo.gameABI;
// const recURL = ABIInfo.rec20Url;
// const gameURL = ABIInfo.gameUrl;
// UtilTool.printLog(recURL,gameURL,'xxx');

const TransferRechargeMembership = (type:'success'|'fail') =>{
  var webview = document.getElementById('webview') as HTMLIFrameElement;              
  webview.contentWindow.postMessage({type:'rechargeMembership',data:type}, '*');
}

export enum GoodsType {
    WITHDRAW = 0,        //回撤，值为0
    RANDOM = 1,          //随机，值为1
    REMOVE = 2,          //移除，值为2
    RECEIVE = 3,         //复活，值为3
    MEMBER_MONTH = 4,   //一个月会员，值为4
    MEMBER_SIX_MONTH = 5,//六个月会员，值为5
    MEMBER_YEAR = 6      //年度会员，值为6
}

let t = ['授权失败','Authorization failed','인증 실패','認証に失敗しました'];
let t2 = ['支付失败','payment failed','결제 실패','支払いに失敗しました'];
let t3 = ['余额不足','Insufficient balance','잔액 불충분','残高不足'];
// let languaeGlobal = sessionStorage.getItem('languaeGlobal') == null ? 1 : Number(sessionStorage.getItem('languaeGlobal'))
export class SmartContract {
  private web3: any;
  private contract: any; // rec合约实例
  private contractPlay: any; // 支付 合约实例
  private userAddress: string;
  private goodsType:GoodsType;  // 这个游戏暂时不用这个字段
  private amount:number;  // 购买数量
  private goodsPrice:number;  // 购买数量
    recABI: any;
    gameABI: any;
    recURL: any;
    gameURL: any;
  constructor(account,web3,{recABI,gameABI,recURL,gameURL}) {
    UtilTool.printLog(recABI,gameABI,recURL,gameURL,'recABI,gameABI,recURL,gameURL');
    
    if (!recABI || !gameABI || !recURL || !gameURL) {
        alert('缺少构造合约关键参数，拒绝构造！！！')
    }
    this.recABI = recABI;
    this.gameABI = gameABI;
    this.recURL = recURL;
    this.gameURL = gameURL;
    this.contract = new web3.eth.Contract(recABI as any  , recURL); //rec20合约
    this.contractPlay = new web3.eth.Contract(gameABI as any  , gameURL);//游戏合约
    this.web3 = web3;
    this.userAddress = account;//用户账户
    // UtilTool.printLog(getAllRecord,'getAllRecord');
  }

  /**
   * 上传记录上链的方法
   * @param params 用户上传到链的数据 
   * @param web3 构造后的web3 实例 
   */
  async contractPlayRecord(finishTime,sign){
    try {
      return new Promise<void>(async (reslove1,reject1) =>{
        fn.call(this)
        async function fn  () {
          let {startTime, cancelTime} = UtilTool.calculatedTimeout();
          startTime()
          .then(()=>{
            // reject1()
          })
          .catch(err =>{
            UtilTool.printLog('超时失败');
            
            alert('由于网络波动，请更换网络节点以上传!')
            UtilTool.printLog('网络错误！');
            if (confirm('是否重新尝试上传') == true) {
                //点是，执行function
                cancelTime(); 
                fn.call(this)
                
            } else {
                cancelTime();
                //点否，执行function
                reject1();
            } 
          })
          // UtilTool.printLog(this.contractPlay.methods.record,'this.contractPlay.methods.record');
          try {
            let gasPrice =  await this.web3.eth.getGasPrice();
            UtilTool.printLog('1');
            UtilTool.printLog(finishTime,sign);

            let gas = await this.contractPlay.methods.record(finishTime,sign).estimateGas({from:this.userAddress});
            UtilTool.printLog('2');
            UtilTool.printLog( this.web3,' this.web3');
        
            // this.web3.ethereum.on('accountsChanged', function (accounts) {
            //   UtilTool.printLog("调起了上传弹框:", accounts);
            //   // 检查用户是否授权合约使用可用余额
            //   // 如果 accounts 数组包含当前用户的账户，则用户已授权
            //   // if (accounts.includes(web3.eth.defaultAccount)) {
            //   //   UtilTool.printLog("User has authorized contract to use their available balance.");
            //   // } else {
            //   //   UtilTool.printLog("User has not authorized contract to use their available balance.");
            //   // }
            // });
            cancelTime();
            let uploadStatus = await this.contractPlay.methods.record(finishTime,sign).send({from:this.userAddress , gas ,gasPrice})
            // .on('transactionHash', function(hash){
            //   UtilTool.printLog('调起授权了');
              
            //   cancelTime();
            // })
            UtilTool.printLog('3');

            log(uploadStatus,'状态')
            if (typeof uploadStatus == "object" && uploadStatus.status) {
              reslove1()
              UtilTool.printLog('上传成功');
              return true
            }else{
              return false
            }
          } catch (error) {
            UtilTool.printLog(error,'error');
            
            cancelTime(); 
            reject1();
            UtilTool.printLog('上传可能被拒绝了');
            
          }
        }
      })
      } catch (error) {
        UtilTool.printLog('上传失败',error);
        return false;
      }
  }


  /**
   * 授权流程，授权之前获取用户已授权给我们的可操作金额，可操作金额小于购买的商品价格提醒用户进行再次授权，授权接结束后如果还是小于商品价格直接提示失败，否则进入支付步骤
   */
  /**
   * 
   * @param goods 商品id
   * @returns 
   */
  // 授权方法 [goods]商品类型，授权成功或已授权，获取订单号 [amount]购买数量
    async authorize(goods:GoodsType,amount:number, goodsPrice:number): Promise<void> {
      try {
        return new Promise(async (reslove1,reject1) =>{
            let {startTime, cancelTime} = UtilTool.calculatedTimeout()
            startTime()
            .then(()=>{
              // reject1()
            })
            .catch(err =>{
              UtilTool.printLog('超时失败');
              reject1();
              alert('由于网络波动，请更换网络节点以支付。')
              UtilTool.printLog('网络错误！');
            })
            this.goodsType = goods;//保存订单类型
            this.amount = amount
            this.goodsPrice = goodsPrice

            UtilTool.printLog('开始授权支付流程前 === ');
            let authorizedPrice = await this.contract.methods.allowance(this.userAddress, this.gameURL).call();
            UtilTool.printLog('已获取用户授权合约可用余额 === ' , authorizedPrice);
            // let goodsPrice = this.amount //await this.contractPlay.methods.prices(this.goodsType).call();
            goodsPrice = await this.formatGoodsPrice(goodsPrice); //

            UtilTool.printLog('已获取当前商品价格 === ' , goodsPrice);
            if (Number(authorizedPrice) < Number(goodsPrice)) {
              log('当前用户授权合约的余额小于当前商品价格需要重新授权 === ');
                //商品价格大于授权金额 让用户授权
                UtilTool.printLog('准备获取用户账户余额 === ' ,this.userAddress);
                let userBalance = await this.contract.methods.balanceOf(this.userAddress).call();
                UtilTool.printLog('已获取用户账户余额 === ',userBalance);
                    // return new Promise(async (reslove,rejcet) =>{
                        UtilTool.printLog('准备调起授权 === ' , this.gameURL);
                        try {
                          let approve = await  this.contract.methods.approve(this.gameURL, userBalance).send(
                            {from: this.userAddress})
                            .on('confirmation', async (confirmationNumber, receipt) =>{
                                cancelTime()
                                if (confirmationNumber < 2) {
                                  UtilTool.printLog(confirmationNumber,'正在确认链');
                                }
                                //等于表示授权已确认
                                if (confirmationNumber == 1) {
                                    UtilTool.printLog('授权余额已在链上 === ');
                                    let authorizePrice = await this.contract.methods.allowance(this.userAddress, this.gameURL).call();
                                    if (Number(authorizePrice) >= Number(goodsPrice)) {
                                      log('当前授权余额大于或等于商品价格返回成功 === ');
                                      reslove1()
                                    }else{
                                      log('当前授权余额依然小于商品价格返回失败 === ');
                                      reject1()
                                    };
                                }
                            }).
                            on('error',() =>{
                                reject1()
                                UtilTool.printLog('拒绝报错')
                                cancelTime()
                            })    
                        } catch (error) {
                            UtilTool.printLog(error, '授权报错')
                            reject1()
                            cancelTime()
                        }
                    // })      
            }else{
              cancelTime();
              reslove1();
            }
        })

      } catch (error) {
        UtilTool.printLog(error,'authorize 授权失败');
        
    }
    }
    async play(orderId) {
      UtilTool.printLog('进入支付',orderId);
      if (!orderId) {
          alert('商品id为空！！')
      }
      try {

          let gas = await this.contractPlay.methods.buy(orderId, this.goodsPrice).estimateGas({from:this.userAddress});
          let gasPrice =  await this.web3.eth.getGasPrice();
          UtilTool.printLog(gas,'gasxxxxx');
          
          UtilTool.printLog(BigNumber(gas).toString(10), gasPrice,'gas , gasPrice');
          
          const transfer = await this.contractPlay.methods.buy(orderId, this.goodsPrice).send({ from: this.userAddress , gas , gasPrice });
          UtilTool.printLog('结果',transfer);
          if (transfer.blockHash) {
              return transfer;
          }
      } catch (error) {
        UtilTool.printLog(error,'error');
        
        return false
      }
    }

    /**
   * 格式化商品价格
   * @param goodsPrice 原商品价格
   */
    async formatGoodsPrice (goodsPrice):Promise<any>{
      let tokenDecimals = await this.contract.methods.decimals().call((error, decimals) => {
        if (error) {
          alert('获取代币精度失败:' + error)
        }
        else {
          UtilTool.printLog('代币精度 :',decimals);
        }
      })

      tokenDecimals = parseInt(tokenDecimals)
      return parseFloat(goodsPrice) * Math.pow(10, tokenDecimals)

      // return await web3.utils.toWei((parseFloat(goodsPrice) * Math.pow(10, tokenDecimals)).toString());
    }
}